﻿using ACC.Business;
using ACC.Data.ACCLog;
using ACC.Data.Comm;
using ACC.Data.Line;
using ACC.Device;
using ACC.Device.PLC;
using ACC.Device.PLC.Siemens;
using ACC.LineDevice.KukaPack;
using ACC.Util.Convert;
using iPlant.Features.WOMSClient.Business;
using iPlant.Features.WOMSClient.Interface;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;

namespace Script
{
    public class 电芯线 : LineProcessKukaPack
    {
        public 电芯线(LineData data)
            : base(data)
        {
        }
        
        /// <summary>
        /// 初始化ACC连接PLC使用的Driver配置
        /// </summary>
        protected override void InitDriver()
        {
            base.InitDriver();

            /*
             * 以下代码用于设定使用虚拟PLC
             */

            ////获取在Config中配置的Device对应的Driver
            PLCDriver driver = (PLCDriver)LineDeviceDrivers["PLC_10"];
            driver.SetBaseDriver(new VSiemensDriver_Base(driver.DeviceCfg));
            driver = (PLCDriver)LineDeviceDrivers["PLC_20"];
            driver.SetBaseDriver(new VSiemensDriver_Base(driver.DeviceCfg));
        }
    }

    /// <summary>
    /// WOMS连动、重写站脚本
    /// </summary>
    public class StnProcessEx : StnProcessKukaPack
    {
        //工单模块对象
        public IWOMSClient _womsProcess = null;

        public StnProcessEx(StnRunningData data)
            : base(data)
        {
        }

        protected override void CreateBusinessLogic()
        {
            base.CreateBusinessLogic();
            //初始化工单模块
            _womsProcess = new WOMSCilentForSqlServer(_data, this.Device);
            

        }

        //protected override ACCDevice CreateDevice()
        //{
        //    //使用指定Device
        //    DeviceForWOMS d = new DeviceForWOMS(_data, lineProcess.LineDeviceDrivers[_data.StnCfg.Device.Name]);
        //    d.NeedSendTime = true;
        //    d.NeedCheckSum = false;
        //    //d.SetStartPosition(190);
        //    return d;
        //}


        public override void ChangePartNo(RuningPartNo newpartno)
        {
            //工单不为空时，调用工单模块的换型
            if (newpartno != null)
            {
                _womsProcess.ChangeOver(newpartno.BomCfg.PartNo);
                //BOM变化后需要重新刷新数据
                GetComponents(newpartno);
            }

            base.ChangePartNo(newpartno);
        }

        public override ACCCode ReadLoadParam(ACCDevice dev, out ACCDevice.LoadParam param)
        {
            ACCCode rs = base.ReadLoadParam(dev, out param);

            if (rs == ACCCode.ACCOK)
            {
                /*
                 *检测工单状态
                 *工单数量是否已满（参数控制）
                 *PartNo是否对应
                 *BOM是否需要下载
                 *PartType&ProcessData是否需要下载

                 *没有工单需要生产
                 *WOMS_NO_WorkOrder = ACCCode.UserDef_100;
                 *更新内存失败
                 *WOMS_Modify_Memory_Fail = ACCCode.UserDef_101;
                 *Stn未启动
                 *WOMS_StnIsNotRunning = ACCCode.UserDef_102;
                 *检查工单失败
                 *WOMS_CheckWorkOrder_Fail = ACCCode.UserDef_103;
                 *工单已满
                 *WOMS_CheckWorkOrder_Full = ACCCode.UserDef_104;
                 *PartNo不匹配
                 *WOMS_CheckWorkOrder_PartNo_Mismatch = ACCCode.UserDef_105;
                 *BOM的发布号不匹配
                 *WOMS_CheckWorkOrder_BOM_ReleaseCode_Mismatch = ACCCode.UserDef_106;
                 *ProductParameter的发布号不匹配
                 *WOMS_CheckWorkOrder_ProductParameter_ReleaseCode_Mismatch = ACCCode.UserDef_107;
                 *填充工单失败
                 *WOMS_ChargeWorkOrder_Fail = ACCCode.UserDef_108;
                 *保存UnitHistoryRuntime失败
                 *WOMS_UnitHistoryRuntime_Fail = ACCCode.UserDef_109;
                 * 
                 *以上错误编码可根据实际使用进行重新指向
                */

                if (_data.IsFirstStn)
                {
                    DataTable dt = null;
                    string sql = string.Empty;

                    // 获取当前的工单号
                    string currentWoNo = _womsProcess.CurrentWoNo();

                    // 如果工单号为空、说明还没有进行生产
                    if (string.IsNullOrEmpty(currentWoNo))
                    {
                        // 从下达的工单中取得一个工单
                        // 取得方法:已下达的工单（STATUS = 1）按照【SORT】字段升序排序后的第一个工单
                        sql = string.Format("SELECT TOP 1 * FROM ACC_WO_WORKORDER_HEADER WHERE STATUS = 1 ORDER BY SORT");
                        dt = ACC.Data.DataManager.DBHelper.Query(sql);

                        if (dt != null && dt.Rows.Count > 0)
                        {
                            // 即将生产的工单号
                            currentWoNo = dt.Rows[0]["WONO"].ToString();

                            // 更新当前工单
                            _womsProcess.SetCurrentWorkOrder(currentWoNo);

                            StnEventLog.Log(_data, StnLog.LogType.Event, "WoNo = " + currentWoNo);
                        }
                        else
                        {
                            return ACCCode.UserDef_100;
                        }
                    }

                    // 检查工单状态
                    rs = _womsProcess.CheckWorkOrder(_data.IsFirstStn);

                    // 返回ACCCode.UserDef_104（工单已满）、则获取下一个工单
                    if (rs == ACCCode.UserDef_104)
                    {
                        // 从下达的工单中取得下一个工单
                        // 取得方法:已下达的工单（STATUS = 1）按照【SORT】字段升序排序、工单号不等于当前工单号的第一个工单作为下一个要生产的工单
                        sql = string.Format("SELECT TOP 1 * FROM ACC_WO_WORKORDER_HEADER WHERE STATUS = 1 and WONO != '{0}' ORDER BY SORT", currentWoNo);
                        dt = ACC.Data.DataManager.DBHelper.Query(sql);

                        if (dt != null && dt.Rows.Count > 0)
                        {
                            // 获取该工单的产品型号
                            string newPartNo = dt.Rows[0]["PARTNO"].ToString();
                            RuningPartNo newRuningPartNo = _data.StnCfg.LineCfg.LineData.RunningData.RunningPartNos[newPartNo];

                            // 如果当前ACC运行的产品型号和即将生产工单的产品型号不一致，则发起ACC换型
                            //if (_data.PartNo != newRuningPartNo && newRuningPartNo != null)
                            //{
                            //    // ACC换型
                            //    // 疑问:如何通知PLC也进行换型 ？？？？
                            //    ChangePartNo(newRuningPartNo);
                            //}
                            // 即将生产的工单号
                            currentWoNo = dt.Rows[0]["WONO"].ToString();

                            // 更新当前工单
                            _womsProcess.SetCurrentWorkOrder(currentWoNo);

                            StnEventLog.Log(_data, StnLog.LogType.Event, "WoNo = " + currentWoNo);
                        }
                        else
                        {
                            // 没有工单需要生产
                            rs = ACCCode.UserDef_100;
                        }
                    }
                    else if (rs == ACCCode.ACCOK)
                    {
                        // 是否需要检查产品型号 ？
                        #region
                        //// 根据工单号取得工单详情
                        //sql = string.Format("SELECT * FROM ACC_WO_WORKORDER_HEADER WHERE WONO = '{0}' ", currentWoNo);
                        //dt = ACC.Data.DataManager.DBHelper.Query(sql);
                        //if (dt != null && dt.Rows.Count > 0)
                        //{
                        //    // 获取当前工单的产品型号
                        //    string newPartNo = dt.Rows[0]["PARTNO"].ToString();
                        //    RuningPartNo newRuningPartNo = _data.StnCfg.LineCfg.LineData.RunningData.RunningPartNos[newPartNo];
                        //    // 如果当前ACC运行的产品型号和即将生产工单的产品型号不一致，则发起ACC换型
                        //    if (_data.PartNo != newRuningPartNo && newRuningPartNo != null)
                        //    {
                        //        // ACC换型
                        //        // 疑问:如何通知PLC也进行换型 ？？？？
                        //        ChangePartNo(newRuningPartNo);
                        //    }
                        //}
                        #endregion
                    }
                }
                return _womsProcess.CheckWorkOrder(_data.IsFirstStn);
            }

            return rs;
        }

        public override ACCCode SendLoadResult(ACCDevice dev, ACCDevice.LoadResult result)
        {
            string msg;

            if (result.ErrorCode == ACCCode.ACCOK)
            {
                //更新工单明细信息
                _womsProcess.ChargeWorkOrder(_data.LastTryLoadUnit.UnitSN, "", "", false, out msg);
                //插入UnitHistory对应的BOM和生产数据的版本号
                _womsProcess.UpdateUnitHistoryRuntime(_data.LastTryLoadUnit.LastHist);

                if (msg != "")
                {
                    StnEventLog.Log(_data, StnLog.LogType.Error, msg);
                }
            }

            return base.SendLoadResult(dev, result);
        }

        /// <summary>
        /// 发送UnLoad信息
        /// </summary>
        /// <param name="dev"></param>
        /// <param name="result"></param>
        /// <returns></returns>
        public override ACCCode SendUnloadResult(ACCDevice dev, ACCDevice.UnloadResult result)
        {
            string msg;

            if (result.ErrorCode == ACCCode.ACCOK)
            {
                //将工单明细中Unit的状态更新为FG
                _womsProcess.ChargeWorkOrder(_data.LastUnloadUnit.UnitSN, "", "", _data.LastUnloadUnit.Status == WIPUnit.UnitStatus.FG ? true : false, out msg);
            }

            return base.SendUnloadResult(dev, result);
        }

        /// <summary>
        /// 将产品类别描述转换为工单列表
        /// </summary>
        /// <param name="aryPartTypeID"></param>
        /// <param name="aryPartTypeDesc"></param>
        /// <param name="checksum"></param>
        public void GetPartTypeDesc(out uint[] aryPartTypeID, out string[] aryPartTypeDesc, out uint checksum)
        {
            StnEventLog.Log(_data, StnLog.LogType.Event, "GetPartTypeDesc Begin");
            _womsProcess.GetPartTypeDesc(_data.StnCfg.LineCfg.Line, out aryPartTypeID, out aryPartTypeDesc, out checksum);

            StnEventLog.Log(_data, StnLog.LogType.Event, "GetPartTypeDesc End");
        }

        /// <summary>
        /// 将工单的需要转换为PartTypeID
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        public uint GetPartTypeID(int id)
        {
            var workorder = _womsProcess.GetWorkOrderHeaderByID(id);
            if (workorder != null)
            {
                _womsProcess.SetCurrentWorkOrder(workorder.WONo);

                if (!_lineData.Cfg.BomCfg.ContainsKey(workorder.PartNo))
                {
                    return 0;
                }

                return _lineData.Cfg.BomCfg[workorder.PartNo].PartTypeID;
            }
            else
            {
                return 0;
            }
        }


    }

    /// <summary>
    /// 重新PLC Device，将下载型号列表改为下载工单列表
    /// </summary>
    //public class DeviceForWOMS : SiemensWithMC3000
    //{
    //    public DeviceForWOMS(StnRunningData data, ACCDriver driver)
    //        : base(data, driver)
    //    {
    //        StnEventLog.Log(data, StnLog.LogType.Event, "DeviceForWOMS");
    //    }

    //    /// <summary>
    //    /// 调用StnProcess里的业务逻辑
    //    /// </summary>
    //    /// <param name="aryPartTypeID"></param>
    //    /// <param name="aryPartTypeDesc"></param>
    //    /// <param name="checksum"></param>
    //    protected override void GetPartTypeDesc(out uint[] aryPartTypeID, out string[] aryPartTypeDesc, out uint checksum)
    //    {
    //        StnEventLog.Log(_stnData, StnLog.LogType.Event, "GetPartTypeDesc");
    //        StnProcessEx stnProcess = (StnProcessEx)LineManager.Lines[_lineData.Line].StnProcesses[_stnData.StnCfg];
    //        stnProcess.GetPartTypeDesc(out aryPartTypeID, out aryPartTypeDesc, out checksum);
    //    }

    //    /// <summary>
    //    /// 重写函数，将工单列表写入到PLC
    //    /// </summary>
    //    /// <returns></returns>
    //    protected override bool WritePartTypeACC()
    //    {
    //        //return base.WritePartTypeACC();
    //        uint[] aryPartTypeID;
    //        string[] aryPartTypeDesc;
    //        uint checksum = 0;
    //        //此处与原始函数中不同
    //        GetPartTypeDesc(out aryPartTypeID, out aryPartTypeDesc, out checksum);
    //        byte[] data = new byte[56 + (PartTypeDescLength + 4) * aryPartTypeID.Length];
    //        data[2] = 50;
    //        byte[] temp = BitConverter.GetBytes(ByteUtils.ACCPLCUint16Convert((ushort)checksum));
    //        Array.Copy(temp, 0, data, 54, temp.Length);
    //        for (int i = 0; i < aryPartTypeID.Length; i++)
    //        {
    //            temp = BitConverter.GetBytes(ByteUtils.ACCPLCUint16Convert((ushort)aryPartTypeID[i]));
    //            Array.Copy(temp, 0, data, 56 + i * (PartTypeDescLength + 4), temp.Length);
    //            data[56 + i * (PartTypeDescLength + 4) + 2] = (byte)PartTypeDescLength;
    //            data[56 + i * (PartTypeDescLength + 4) + 3] = (byte)aryPartTypeDesc[i].Length;
    //            temp = Encoding.ASCII.GetBytes(aryPartTypeDesc[i]);
    //            Array.Copy(temp, 0, data, 56 + i * (PartTypeDescLength + 4) + 4, temp.Length);
    //        }
    //        return WriteDBBytes(DB191, 0, data.Length, data);
    //    }

    //    /// <summary>
    //    /// 调用StnProcess中PartTypeID转换功能
    //    /// </summary>
    //    /// <param name="htPartTypeDataParam"></param>
    //    /// <returns></returns>
    //    protected override bool ReadPartTypeDataPLC(out System.Collections.Hashtable htPartTypeDataParam)
    //    {
    //        bool r = base.ReadPartTypeDataPLC(out htPartTypeDataParam);
    //        StnProcessEx stnProcess = (StnProcessEx)LineManager.Lines[_lineData.Line].StnProcesses[_stnData.StnCfg];

    //        if (r)
    //        {
    //            htPartTypeDataParam["PartTypeID"] = stnProcess.GetPartTypeID(int.Parse(htPartTypeDataParam["PartTypeID"].ToString()));
    //        }

    //        return r;
    //    }
    //}

}
